#include "glWidget.h"
#include <QKeyEvent>
#include <QDebug>
#include <cmath>

double PI(4*std::atan(1));

GLWidget::GLWidget(QWidget* parent, unsigned int fps)
  : QGLWidget(parent),
    mFramesPainted(0),
    mXRot(45),
    mYRot(45),
    mQuadric(0),
    mQuadricType(0)
{
  connect(&mTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
  mTimer.start(1000/fps);
  mTime.start();
  setFocusPolicy(Qt::StrongFocus);

  qDebug() << "GLWidget started";
}

GLWidget::~GLWidget()
{
  mTimer.stop();
}

void GLWidget::initializeGL()
{
  loadGLTexture("testimage.png", mTextures);
  glEnable(GL_TEXTURE_2D); //enable 2D texture mapping

  glShadeModel(GL_SMOOTH); //smooth shading
  glClearColor(0, 0, 0, 0.5); //black background

  //depth buffer setup
  glClearDepth(1);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  //quadric setup
  mQuadric = gluNewQuadric();
  gluQuadricNormals(mQuadric, GLU_SMOOTH);
  gluQuadricTexture(mQuadric, GL_TRUE);

  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //best perspective correction
}

void GLWidget::resizeGL(int w, int h)
{
  glViewport(0, 0, w, h); //reset viewport

  //setup perspective view
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45, w*1./h, 0.1, 100.);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void GLWidget::paintGL()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen and depth buffer
  glLoadIdentity(); //reset view

  glBindTexture(GL_TEXTURE_2D, mTextures[0]);
  glTranslatef(0, 0, -5);
  glRotatef(mXRot, 1, 0, 0);
  glRotatef(mYRot, 0, 1, 0);

  switch(mQuadricType)
  {
  case 0:
    glTranslatef(0, 0, -1.5);
    gluCylinder(mQuadric, 1, 1, 3, 32, 32);
    break;
  case 1:
    gluDisk(mQuadric, 0.5, 1.5, 32, 32);
    break;
  case 2:
    gluSphere(mQuadric, 1.3, 32, 32);
    break;
  case 3:
    glTranslatef(0, 0, -1.5);
    gluCylinder(mQuadric, 1, 0, 3, 32, 32);
    break;
  }

  //calculate fps
  ++mFramesPainted;
  if (mTime.elapsed() > 1000)
  {
    emit fps(mFramesPainted * 1000 / mTime.restart());
    mFramesPainted = 0;
  }
}

void GLWidget::keyPressEvent(QKeyEvent *e)
{
  switch (e->key())
  {
  case Qt::Key_Left:
    mYRot -= 0.5;
    break;
  case Qt::Key_Right:
    mYRot += 0.5;
    break;
  case Qt::Key_Up:
    mXRot -= 0.5;
    break;
  case Qt::Key_Down:
    mXRot += 0.5;
    break;
  case Qt::Key_Space:
    mQuadricType = (mQuadricType+1) % 4;
    break;
  default:
    QGLWidget::keyPressEvent(e);
  }
}

void GLWidget::loadGLTexture(const QString &filename, GLuint textures[3])
{
  //load image
  QImage temp(filename);
  if (temp.isNull())
  {
    temp = QImage(16, 16, QImage::Format_RGB32);
    temp.fill(Qt::green);
    qDebug() << "Can't find image";
  }
  QImage glformatted(QGLWidget::convertToGLFormat(temp)); //convert to gl format

  glGenTextures(1, &textures[0]); //create 1 texture

  glBindTexture(GL_TEXTURE_2D, textures[0]); //create 2d texture at ret
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //filter when image is smaller than texture: good filter
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //filter when image is larger than texture: good filter
  glTexImage2D(GL_TEXTURE_2D, //create 2d texture
               0, //level of detail
               3, //number of data components (rgb = 3)
               glformatted.width(), glformatted.height(), //size of texture
               0, //border
               GL_RGBA, //use rgb in this order
               GL_UNSIGNED_BYTE, //image data is unsigned bytes
               glformatted.bits()); //pointer to image data
}
